//= require jquery-ui/escape-selector
//= require jquery-ui/form-reset-mixin
//= require jquery-ui/labels
//= require jquery-ui/widget

/*!
 * jQuery UI Checkboxradio 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Checkboxradio
//>>group: Widgets
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
//>>docs: http://api.jqueryui.com/checkboxradio/
//>>demos: http://jqueryui.com/checkboxradio/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.structure: ../../themes/base/checkboxradio.css
//>>css.theme: ../../themes/base/theme.css

( function( factory ) {
  if ( typeof define === "function" && define.amd ) {

    // AMD. Register as an anonymous module.
    define( [
      "jquery",
      "../escape-selector",
      "../form-reset-mixin",
      "../labels",
      "../widget"
    ], factory );
  } else {

    // Browser globals
    factory( jQuery );
  }
}( function( $ ) {

  $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
    version: "1.12.1",
    options: {
      disabled: null,
      label: null,
      icon: true,
      classes: {
        "ui-checkboxradio-label": "ui-corner-all",
        "ui-checkboxradio-icon": "ui-corner-all"
      }
    },

    _getCreateOptions: function() {
      var disabled, labels;
      var that = this;
      var options = this._super() || {};

      // We read the type here, because it makes more sense to throw a element type error first,
      // rather then the error for lack of a label. Often if its the wrong type, it
      // won't have a label (e.g. calling on a div, btn, etc)
      this._readType();

      labels = this.element.labels();

      // If there are multiple labels, use the last one
      this.label = $( labels[ labels.length - 1 ] );
      if ( !this.label.length ) {
        $.error( "No label found for checkboxradio widget" );
      }

      this.originalLabel = "";

      // We need to get the label text but this may also need to make sure it does not contain the
      // input itself.
      this.label.contents().not( this.element[ 0 ] ).each( function() {

        // The label contents could be text, html, or a mix. We concat each element to get a
        // string representation of the label, without the input as part of it.
        that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
      } );

      // Set the label option if we found label text
      if ( this.originalLabel ) {
        options.label = this.originalLabel;
      }

      disabled = this.element[ 0 ].disabled;
      if ( disabled != null ) {
        options.disabled = disabled;
      }
      return options;
    },

    _create: function() {
      var checked = this.element[ 0 ].checked;

      this._bindFormResetHandler();

      if ( this.options.disabled == null ) {
        this.options.disabled = this.element[ 0 ].disabled;
      }

      this._setOption( "disabled", this.options.disabled );
      this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
      this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );

      if ( this.type === "radio" ) {
        this._addClass( this.label, "ui-checkboxradio-radio-label" );
      }

      if ( this.options.label && this.options.label !== this.originalLabel ) {
        this._updateLabel();
      } else if ( this.originalLabel ) {
        this.options.label = this.originalLabel;
      }

      this._enhance();

      if ( checked ) {
        this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
        if ( this.icon ) {
          this._addClass( this.icon, null, "ui-state-hover" );
        }
      }

      this._on( {
        change: "_toggleClasses",
        focus: function() {
          this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
        },
        blur: function() {
          this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
        }
      } );
    },

    _readType: function() {
      var nodeName = this.element[ 0 ].nodeName.toLowerCase();
      this.type = this.element[ 0 ].type;
      if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
        $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
            " and element.type=" + this.type );
      }
    },

    // Support jQuery Mobile enhanced option
    _enhance: function() {
      this._updateIcon( this.element[ 0 ].checked );
    },

    widget: function() {
      return this.label;
    },

    _getRadioGroup: function() {
      var group;
      var name = this.element[ 0 ].name;
      var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";

      if ( !name ) {
        return $( [] );
      }

      if ( this.form.length ) {
        group = $( this.form[ 0 ].elements ).filter( nameSelector );
      } else {

        // Not inside a form, check all inputs that also are not inside a form
        group = $( nameSelector ).filter( function() {
          return $( this ).form().length === 0;
        } );
      }

      return group.not( this.element );
    },

    _toggleClasses: function() {
      var checked = this.element[ 0 ].checked;
      this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );

      if ( this.options.icon && this.type === "checkbox" ) {
        this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
            ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
      }

      if ( this.type === "radio" ) {
        this._getRadioGroup()
            .each( function() {
              var instance = $( this ).checkboxradio( "instance" );

              if ( instance ) {
                instance._removeClass( instance.label,
                    "ui-checkboxradio-checked", "ui-state-active" );
              }
            } );
      }
    },

    _destroy: function() {
      this._unbindFormResetHandler();

      if ( this.icon ) {
        this.icon.remove();
        this.iconSpace.remove();
      }
    },

    _setOption: function( key, value ) {

      // We don't allow the value to be set to nothing
      if ( key === "label" && !value ) {
        return;
      }

      this._super( key, value );

      if ( key === "disabled" ) {
        this._toggleClass( this.label, null, "ui-state-disabled", value );
        this.element[ 0 ].disabled = value;

        // Don't refresh when setting disabled
        return;
      }
      this.refresh();
    },

    _updateIcon: function( checked ) {
      var toAdd = "ui-icon ui-icon-background ";

      if ( this.options.icon ) {
        if ( !this.icon ) {
          this.icon = $( "<span>" );
          this.iconSpace = $( "<span> </span>" );
          this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
        }

        if ( this.type === "checkbox" ) {
          toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
          this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
        } else {
          toAdd += "ui-icon-blank";
        }
        this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
        if ( !checked ) {
          this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
        }
        this.icon.prependTo( this.label ).after( this.iconSpace );
      } else if ( this.icon !== undefined ) {
        this.icon.remove();
        this.iconSpace.remove();
        delete this.icon;
      }
    },

    _updateLabel: function() {

      // Remove the contents of the label ( minus the icon, icon space, and input )
      var contents = this.label.contents().not( this.element[ 0 ] );
      if ( this.icon ) {
        contents = contents.not( this.icon[ 0 ] );
      }
      if ( this.iconSpace ) {
        contents = contents.not( this.iconSpace[ 0 ] );
      }
      contents.remove();

      this.label.append( this.options.label );
    },

    refresh: function() {
      var checked = this.element[ 0 ].checked,
          isDisabled = this.element[ 0 ].disabled;

      this._updateIcon( checked );
      this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
      if ( this.options.label !== null ) {
        this._updateLabel();
      }

      if ( isDisabled !== this.options.disabled ) {
        this._setOptions( { "disabled": isDisabled } );
      }
    }

  } ] );

  return $.ui.checkboxradio;

} ) );
